package com.jun.admin.core.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.jun.admin.core.mapper.JunStudentMapper;
import com.jun.admin.core.model.JunStudent;
import com.jun.admin.core.utils.ExcelValidUtil;
import com.jun.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author yuejun.li
 * @date 2024/10/8 10:11:08
 */
// 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class JunStudentListener extends AnalysisEventListener<JunStudent> {

    //每隔100条清理一次list，实际可以定为3000
    private static final int BATCH_COUNT = 100;

    //缓存数据
    private List<JunStudent> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    //mapper
    private JunStudentMapper junStudentMapper;

    public JunStudentListener(JunStudentMapper junStudentMapper) {
        this.junStudentMapper = junStudentMapper;
    }

    /**
     * 头部数据（每个sheet只进来一次）
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        List<String> headList = Arrays.asList(new String[]{"学生名称", "年龄", "出生日期", "是否活跃"});

        for (Map.Entry<Integer, String> entry : headMap.entrySet()) {
            if(!Objects.equals(headList.get(entry.getKey()),entry.getValue())){
                throw new ServiceException("表头不符合，请重新查看");
            }
        }
    }

    /**
     * 这个每一条数据解析都会来调用
     */
    @Override
    public void invoke(JunStudent junStudent, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSON.toJSONString(junStudent));
        //校验
        ExcelValidUtil.valid(junStudent,analysisContext);
        cachedDataList.add(junStudent);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 就会来调用该方法
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        log.info("所有数据解析完成！");
        saveData();
    }

    /**
     * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
        }
    }

    /**
     * 存储数据库
     */
    private void saveData() {
        log.info("{}条数据，开始存储数据库！", cachedDataList.size());
        junStudentMapper.insertList(cachedDataList);
        log.info("存储数据库成功！");
    }
}
